import socket
import struct
import threading
import time
import configparser
import os
from datetime import datetime
from modules.logger_config import get_server_logger

# 配置日志
logger = get_server_logger()

class VendingServer:
    def __init__(self, config_file="config.ini"):
        # 加载配置文件
        self.config = configparser.ConfigParser()
        self.config.read(config_file, encoding='utf-8')
        
        # 从配置文件读取参数
        self.host = self.config.get('server', 'host')
        self.port = self.config.getint('server', 'port')
        
        self.server_socket = None
        self.clients = {}  # 存储客户端连接信息
        self.running = False
        
    def start(self):
        """启动服务器"""
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((self.host, self.port))
            self.server_socket.listen(5)
            self.running = True
            
            logger.info(f"服务器启动成功，监听 {self.host}:{self.port}")
            print(f"=== 售货机服务器已启动 ===")
            print(f"监听地址: {self.host}:{self.port}")
            print(f"等待客户端连接...")
            print("=" * 50)
            
            while self.running:
                try:
                    client_socket, client_address = self.server_socket.accept()
                    logger.info(f"新客户端连接: {client_address}")
                    
                    # 为每个客户端创建处理线程
                    client_thread = threading.Thread(
                        target=self.handle_client,
                        args=(client_socket, client_address),
                        daemon=True
                    )
                    client_thread.start()
                    
                except Exception as e:
                    if self.running:
                        logger.error(f"接受连接时出错: {e}")
                        
        except Exception as e:
            logger.error(f"启动服务器失败: {e}")
        finally:
            self.stop()
    
    def stop(self):
        """停止服务器"""
        self.running = False
        if self.server_socket:
            self.server_socket.close()
        logger.info("服务器已停止")
    
    def build_frame(self, control_code, data_str=""):
        """构建协议帧"""
        # 帧起始符
        frame = bytearray([0xFA])
        
        # 控制码
        frame.append(control_code)
        
        # 数据域长度 (2字节，大端序)
        data_bytes = data_str.encode('utf-8') if data_str else b''
        data_length = len(data_bytes)
        frame.extend(struct.pack('>H', data_length))
        
        # 数据域
        frame.extend(data_bytes)
        
        # 帧结束符
        frame.append(0xFF)
        
        return frame
    
    def parse_frame(self, frame):
        """解析协议帧"""
        if len(frame) < 5:
            return None
        
        # 检查帧起始符和结束符
        if frame[0] != 0xFA or frame[-1] != 0xFF:
            return None
        
        control_code = frame[1]
        data_length = struct.unpack('>H', frame[2:4])[0]
        
        # 检查数据长度是否匹配
        if len(frame) != 5 + data_length:
            return None
        
        data = frame[4:4+data_length].decode('utf-8') if data_length > 0 else ""
        
        return {
            'control_code': control_code,
            'data_length': data_length,
            'data': data,
            'raw_frame': frame  # 保存原始帧数据
        }
    
    def frame_to_hex(self, frame):
        """将帧转换为十六进制字符串显示"""
        raw_frame = frame.get('raw_frame', b'')
        if not raw_frame:
            return "无原始数据"
        
        # 将字节数组转换为十六进制字符串
        hex_str = ' '.join(f'{b:02X}' for b in raw_frame)
        
        # 添加分隔符和说明
        result = f"[{len(raw_frame)}字节] {hex_str}"
        
        # 添加帧结构说明
        if len(raw_frame) >= 5:
            start = raw_frame[0]
            control = raw_frame[1]
            length_bytes = raw_frame[2:4]
            data_bytes = raw_frame[4:-1] if len(raw_frame) > 5 else b''
            end = raw_frame[-1]
            
            result += f"\n        | 起始符:0x{start:02X} | 控制码:0x{control:02X} | 长度:{struct.unpack('>H', length_bytes)[0]} | 数据:{data_bytes.hex() if data_bytes else '无'} | 结束符:0x{end:02X}"
        
        return result
    
    def send_frame(self, client_socket, frame):
        """发送帧数据"""
        try:
            client_socket.sendall(frame)
            return True
        except Exception as e:
            logger.error(f"发送数据失败: {e}")
            return False
    
    def handle_client(self, client_socket, client_address):
        """处理客户端连接"""
        client_id = f"{client_address[0]}:{client_address[1]}"
        self.clients[client_id] = {
            'socket': client_socket,
            'address': client_address,
            'terminal_id': None,
            'last_heartbeat': time.time()
        }
        
        buffer = bytearray()
        
        try:
            while self.running:
                data = client_socket.recv(1024)
                if not data:
                    logger.info(f"客户端 {client_id} 断开连接")
                    break
                
                buffer.extend(data)
                
                # 处理缓冲区中的所有完整帧
                while buffer:
                    # 查找帧起始符
                    start_idx = buffer.find(0xFA)
                    if start_idx == -1:
                        buffer.clear()
                        break
                    
                    # 移除起始符之前的所有数据
                    if start_idx > 0:
                        buffer = buffer[start_idx:]
                    
                    # 检查是否有足够的数据获取数据长度
                    if len(buffer) < 5:  # 至少需要5字节(FA+控制码+2字节长度+FF)
                        break
                    
                    # 获取数据长度
                    data_length = struct.unpack('>H', buffer[2:4])[0]
                    frame_length = 5 + data_length  # 帧总长度
                    
                    # 检查是否收到了完整的一帧
                    if len(buffer) < frame_length:
                        break
                    
                    # 提取完整帧
                    frame_data = buffer[:frame_length]
                    buffer = buffer[frame_length:]
                    
                    # 解析帧
                    parsed = self.parse_frame(frame_data)
                    if parsed:
                        self.handle_frame(client_socket, client_id, parsed)
                    else:
                        logger.warning(f"客户端 {client_id} 解析帧失败")
                        
        except Exception as e:
            logger.error(f"处理客户端 {client_id} 时出错: {e}")
        finally:
            # 清理客户端连接
            if client_id in self.clients:
                del self.clients[client_id]
            client_socket.close()
    
    def handle_frame(self, client_socket, client_id, frame):
        """处理接收到的帧"""
        control_code = frame['control_code']
        data = frame['data']
        timestamp = datetime.now().strftime("%H:%M:%S")
        
        # 显示接收到的消息
        print(f"\n[{timestamp}] 客户端 {client_id}")
        print(f"控制码: 0x{control_code:02X}")
        print(f"数据: {data}")
        
        # 打印完整报文（十六进制格式）
        frame_hex = self.frame_to_hex(frame)
        print(f"完整报文: {frame_hex}")
        print("-" * 50)
        
        if control_code == 0x01:  # 登录请求
            self.handle_login(client_socket, client_id, data)
            
        elif control_code == 0x03:  # 心跳
            self.handle_heartbeat(client_socket, client_id)
            
        elif control_code == 0x06:  # 开门响应
            self.handle_open_door_response(client_id, data)
            
        elif control_code == 0x07:  # 关门信息
            self.handle_close_door_info(client_socket, client_id, data)
            
        elif control_code == 0x0A:  # 异常信息
            self.handle_exception_info(client_socket, client_id, data)
            
        else:
            logger.warning(f"未知的控制码: 0x{control_code:02X}")
            print(f"⚠️  未知控制码: 0x{control_code:02X}")
    
    def handle_login(self, client_socket, client_id, terminal_id):
        """处理登录请求"""
        print(f"🔐 登录请求 - 终端ID: {terminal_id}")
        
        # 存储终端ID
        if client_id in self.clients:
            self.clients[client_id]['terminal_id'] = terminal_id
        
        # 发送登录成功响应
        frame = self.build_frame(0x02, "SUCCESS")
        frame_hex = ' '.join(f'{b:02X}' for b in frame)
        print(f"📤 发送响应: [{len(frame)}字节] {frame_hex}")
        
        if self.send_frame(client_socket, frame):
            print(f"✅ 登录成功响应已发送")
        else:
            print(f"❌ 登录成功响应发送失败")
    
    def handle_heartbeat(self, client_socket, client_id):
        """处理心跳"""
        print(f"💓 心跳请求")
        
        # 更新最后心跳时间
        if client_id in self.clients:
            self.clients[client_id]['last_heartbeat'] = time.time()
        
        # 发送心跳响应
        frame = self.build_frame(0x04)
        frame_hex = ' '.join(f'{b:02X}' for b in frame)
        print(f"📤 发送响应: [{len(frame)}字节] {frame_hex}")
        
        if self.send_frame(client_socket, frame):
            print(f"✅ 心跳响应已发送")
        else:
            print(f"❌ 心跳响应发送失败")
    
    def handle_open_door_response(self, client_id, data):
        """处理开门响应"""
        parts = data.split(':', 1)
        if len(parts) == 2:
            command_id, status = parts
            status_text = {1: "开门成功", 2: "开门失败"}.get(int(status), "未知状态")
            print(f"🚪 开门响应 - 指令ID: {command_id}, 状态: {status_text}")
        else:
            print(f"⚠️  开门响应格式错误: {data}")
    
    def handle_close_door_info(self, client_socket, client_id, data):
        """处理关门信息"""
        parts = data.split(':')
        if len(parts) == 4:
            command_id, door_id, status, video_file = parts
            status_text = {1: "关门成功", 2: "关门失败"}.get(int(status), "未知状态")
            print(f"🚪 关门信息 - 柜门: {door_id}, 状态: {status_text}, 视频:{video_file}")
            
            # 发送关门信息响应
            frame = self.build_frame(0x08, "CLOSED")
            frame_hex = ' '.join(f'{b:02X}' for b in frame)
            print(f"📤 发送响应: [{len(frame)}字节] {frame_hex}")
            
            if self.send_frame(client_socket, frame):
                print(f"✅ 关门信息响应已发送")
            else:
                print(f"❌ 关门信息响应发送失败")
        else:
            print(f"⚠️  关门信息格式错误: {data}")

    def handle_exception_info(self, client_socket, client_id, data):
        """处理异常信息"""
        # 数据域现在只包含异常代码
        error_code = data.strip()
        if error_code.isdigit():
            # 获取异常描述用于显示
            error_desc = self._get_exception_description(error_code)
            print(f"🚨 异常信息 - 代码: {error_code}, 描述: {error_desc}")
            
            # 根据异常代码确定处理结果
            response = self._get_exception_response(error_code)
            
            # 发送异常信息响应
            response_data = f"{error_code}:{response}"
            frame = self.build_frame(0x0B, response_data)
            frame_hex = ' '.join(f'{b:02X}' for b in frame)
            print(f"📤 发送响应: [{len(frame)}字节] {frame_hex}")
            
            if self.send_frame(client_socket, frame):
                print(f"✅ 异常信息响应已发送 - 处理结果: {response}")
            else:
                print(f"❌ 异常信息响应发送失败")
        else:
            print(f"⚠️  异常信息格式错误: {data}")
    
    def _get_exception_description(self, error_code):
        """根据异常代码获取异常描述"""
        error_descriptions = {
            "401": "电磁锁连接失败",
            "402": "摄像头初始化失败",
            "403": "串口通信异常",
            "404": "门状态检测异常",
            "405": "视频录制失败",
            "406": "网络连接异常",
            "407": "硬件设备故障",
            "408": "系统资源不足",
            "409": "配置文件错误",
            "410": "其他系统异常",
            "411": "录像上传失败",
            "412": "上传录像出错"
        }
        return error_descriptions.get(error_code, "未知异常")
    
    def _get_exception_response(self, error_code):
        """根据异常代码获取处理结果"""
        error_code = int(error_code)
        
        # 根据异常代码返回不同的处理建议
        if error_code == 401:  # 电磁锁连接失败
            return "MAINTENANCE"
        elif error_code == 402:  # 摄像头初始化失败
            return "RESTART"
        elif error_code == 403:  # 串口通信异常
            return "RESTART"
        elif error_code == 404:  # 门状态检测异常
            return "MAINTENANCE"
        elif error_code == 405:  # 视频录制失败
            return "IGNORE"
        elif error_code == 406:  # 网络连接异常
            return "RESTART"
        elif error_code == 407:  # 硬件设备故障
            return "MAINTENANCE"
        elif error_code == 408:  # 系统资源不足
            return "RESTART"
        elif error_code == 409:  # 配置文件错误
            return "MAINTENANCE"
        elif error_code == 410:  # 其他系统异常
            return "ACK"
        elif error_code == 411:  # 录像上传失败
            return "IGNORE"
        elif error_code == 412:  # 上传录像出错
            return "RESTART"
        else:
            return "ACK"  # 默认确认接收

    def send_open_door_command(self, client_id, command_id, door_id):
        """发送开门指令"""
        if client_id not in self.clients:
            print(f"❌ 客户端 {client_id} 不存在")
            return False
        
        data = f"{command_id}:{door_id}"
        frame = self.build_frame(0x05, data)
        frame_hex = ' '.join(f'{b:02X}' for b in frame)
        client_socket = self.clients[client_id]['socket']
        
        print(f"📤 发送开门指令: [{len(frame)}字节] {frame_hex}")
        
        if self.send_frame(client_socket, frame):
            print(f"🚪 开门指令已发送 - 指令ID: {command_id}, 柜门: {door_id}")
            return True
        else:
            print(f"❌ 开门指令发送失败")
            return False

    def test_exception_response(self, client_id, error_code):
        """测试异常响应"""
        if client_id not in self.clients:
            print(f"❌ 客户端 {client_id} 不存在")
            return False
        
        # 获取异常描述用于显示
        error_desc = self._get_exception_description(error_code)
        
        # 只发送异常代码
        data = error_code
        frame = self.build_frame(0x0A, data)
        frame_hex = ' '.join(f'{b:02X}' for b in frame)
        client_socket = self.clients[client_id]['socket']
        
        print(f"📤 发送测试异常信息: [{len(frame)}字节] {frame_hex}")
        
        if self.send_frame(client_socket, frame):
            print(f"🚨 测试异常信息已发送 - 代码: {error_code}, 描述: {error_desc}")
            return True
        else:
            print(f"❌ 测试异常信息发送失败")
            return False

    def list_clients(self):
        """列出所有连接的客户端"""
        if not self.clients:
            print("📋 当前没有连接的客户端")
            return
        
        print(f"\n📋 当前连接的客户端 ({len(self.clients)} 个):")
        print("-" * 50)
        for client_id, info in self.clients.items():
            terminal_id = info['terminal_id'] or "未登录"
            last_heartbeat = time.time() - info['last_heartbeat']
            print(f"客户端: {client_id}")
            print(f"  终端ID: {terminal_id}")
            print(f"  最后心跳: {last_heartbeat:.1f}秒前")
            print()
    
    def interactive_mode(self):
        """交互模式"""
        print("\n🎮 进入交互模式，输入命令:")
        print("  list - 列出所有客户端")
        print("  open <client_id> <command_id> <door_id> - 发送开门指令")
        print("  quit - 退出服务器")
        print("=" * 50)
        
        while self.running:
            try:
                command = input("\n> ").strip().split()
                if not command:
                    continue
                
                if command[0] == "list":
                    self.list_clients()
                    
                elif command[0] == "open" and len(command) >= 4:
                    client_id = command[1]
                    command_id = command[2]
                    door_id = command[3]
                    self.send_open_door_command(client_id, command_id, door_id)
                    
                elif command[0] == "quit":
                    print("👋 正在关闭服务器...")
                    self.stop()
                    break
                    
                else:
                    print("❌ 无效命令，请重新输入")
                    
            except KeyboardInterrupt:
                print("\n👋 正在关闭服务器...")
                self.stop()
                break
            except Exception as e:
                print(f"❌ 命令执行错误: {e}")


def main():
    """主函数"""
    # 创建服务器实例（从配置文件读取参数）
    server = VendingServer()
    
    # 启动服务器线程
    server_thread = threading.Thread(target=server.start, daemon=True)
    server_thread.start()
    
    # 等待服务器启动
    time.sleep(1)
    
    # 启动交互模式
    server.interactive_mode()


if __name__ == "__main__":
    main()
